/*
 * This project provides a number of implementations for indexing and evaluating
 * <i>Continuous Top-k Queries over Text Streams</i>
 * and has been developped as part of the work described in the article:
 * 
 * Vouzoukidou, N., Amann, B., & Christophides, V. (2012, October). 
 * Processing continuous text queries featuring non-homogeneous scoring functions.
 * In Proceedings of the 21st ACM international conference on Information and 
 * knowledge management (pp. 1065-1074). ACM.
 * http://dl.acm.org/citation.cfm?id=2398404
 * 
 * This software is distributed under the GNU General Public License and as an
 * additional condition of usage, please cite the aforementioned article.
 * 
 * Copyright (C) 2012 ICS/FORTH, Greece and 
 *               2012 LIP6, France
 * 
 * Author: Vouzoukidou Nelly, email: nelly.vouzoukidou (at) gmail (dot) com
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

package gr.forth.ics.continuoustopk;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

/**
 * The Item class represents arriving items as an ordered set of weighted terms,
 * additionally storing the item's score and arrival timestamp. Instances of this
 * class are immutable.
 * 
 * @author Vouzoukidou Nelly, email: nelly.vouzoukidou (at) gmail (dot) com
 */
public class Item extends TermVector {
    private double itemScore;
    private long timestamp;

    /**
     * An empty item, i.e. an item without any terms and with a zero timestamp
     * and item score.
     */
    public static final Item empty = new Item() {
        @Override
        public Term getTerm(int i) {
            return null;
        }

        @Override
        public double getWeight(int i) {
            return 0;
        }

        @Override
        public double getWeight(Term term) {
            return 0;
        }

        @Override
        public int termCount() {
            return 0;
        }

        @Override
        public Iterator<Term> iterator() {
            return Collections.<Term>emptyList().iterator();
        }
    };

    private Item() {
        super();
    }

    /**
     * Creates a new <code>Item</code> object given its arrival timestamp, item score
     * and list of terms.
     * 
     * The weights assigned to the terms are all equal to 
     * <code>1 / (double) terms.length</code>
     * 
     * @see timestamp()
     * @see itemScore()
     * 
     * @param timestamp the timestamp of the item
     * @param itemScore the item's score. Should be in [0, 1]
     * @param terms the list of terms of this item
     * 
     * @throws IllegalArgumentException if itemScore is not in [0, 1]
     */
    public Item(long timestamp, double itemScore, String... terms) {
        super(terms, 1 / (double) terms.length);
        checkItemScore(itemScore);
        
        this.itemScore = itemScore;
        this.timestamp = timestamp;
    }

    /**
     * Creates a new <code>Item</code> object given its arrival timestamp, item score,
     * list of terms and term weights.
     * 
     * @see timestamp()
     * @see itemScore()
     * 
     * The references to terms and the values of weights given as parameter will be copied. 
     * 
     * @param timestamp the timestamp of the item
     * @param itemScore the item's score. Should be in [0, 1]
     * @param terms the array of terms of this item
     * @param weights the array of weights of the item's terms. Should be normalized: the sum of weights should be 1.
     * 
     * @throws IllegalArgumentException if itemScore is not in [0, 1]
     */
    public Item(long timestamp, double itemScore, String[] terms, double[] weights) {
        super(terms, weights);
        
        checkItemScore(itemScore);
        this.itemScore = itemScore;
        this.timestamp = timestamp;
    }

    /**
     * Creates a new <code>Item</code> object with the same terms and term weights
     * as the ones of the item given as a parameter, but with a different item
     * score.
     * 
     * @see itemScore()
     * 
     * @param item the item to be copied
     * @param itemScore the item's score. Should be in [0, 1]
     * 
     * @throws IllegalArgumentException if itemScore is not in [0, 1]
     */
    public Item(Item item, double itemScore) {
        checkItemScore(itemScore);
        
        this.terms = item.terms;
        this.weights = item.weights;
        this.timestamp = item.timestamp;
        this.itemScore = itemScore;
    }
    
    private static void checkItemScore(double itemScore) {
        if (itemScore > 1 || itemScore < 0) {
            throw new IllegalArgumentException("itemScore should be in [0, 1]. Found " + itemScore + " instead.");
        }
    }

    /**
     * Returns the score of this item.
     * 
     * <p> The score is a query-independent estimation of the importance of the 
     * item and remains constant once assigned (in the constructor of 
     * <code>Item</code>). 
     * More accurate interpretation of this value is left up to the end user.
     * An example of interpretation is the estimation of authority of item's 
     * publisher.</p>
     * 
     * @return the score of this item
     */
    public double itemScore() {
        return itemScore;
    }

    /**
     * Returns the timestamp of this item.
     * 
     * <p>The timestamp reflects the time and date of the item's publication.
     * More accurate interpretation of this value is left up to the end user.
     * Examples of interpretation can be i) order of arrival of this item in the 
     * stream of items, ii) seconds/minutes/days after a fixed point in time
     * (e.g. 01/01/2000) etc.
     * </p>
     * @return the timestamp of this item.
     */
    public long timestamp() {
        return timestamp;
    }

    /**
     * Returns a set of the terms of the item.
     * <p>Any changes in the returned result will not affect the actual terms on 
     * the item.</p>
     * 
     * <p>The result of this method is computed by copying all references to the
     * stored <code>Term</code>s. For a faster access on the terms of the item, 
     * use either of the inherited {@link #iterator} and {@link #getTerm(int)} 
     * methods.</p>
     * 
     * @return a set of all Terms of this item represented as a <code>List</code>.
     */
    public List<Term> terms() {
        List<Term> termsSet = new ArrayList<Term>();
        for (Term term : terms) {
            termsSet.add(term);
        }
        return termsSet;
    }

    @Override
    public String toString() {
        return super.toString() + " (" + itemScore + ")";
    }
}
